package plus.easydo.easypush.controller;

import cn.hutool.core.text.CharSequenceUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.scope.AuthGiteeScope;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.*;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import plus.easydo.core.constant.HttpStatus;
import plus.easydo.core.result.DataResult;
import plus.easydo.core.result.R;
import plus.easydo.easypush.annotation.AuthCheck;
import plus.easydo.easypush.oauth.OauthConfigProperties;
import plus.easydo.easypush.oauth.AuthStateRedisCache;
import plus.easydo.easypush.service.UserInfoService;
import plus.easydo.easypush.service.UserPlatformService;
import plus.easydo.easypush.vo.UserInfoVo;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;

/**
 * @author laoyu
 * @version 1.0
 * @date 2022/2/22
 */
@Api("鉴权登录")
@RestController
@RequestMapping("/oauth")
@EnableConfigurationProperties(OauthConfigProperties.class)
public class RestAuthController {

    @Autowired
    OauthConfigProperties oauthConfigProperties;

    @Autowired
    AuthStateRedisCache authStateRedisCache;

    @Autowired
    UserInfoService userInfoService;

    @Autowired
    UserPlatformService userPlatformService;


    @ApiOperation("发起授权登录-重定向至第三方授权")
    @GetMapping("/render/{source}")
    public void renderAuth(@PathVariable("source")String source,HttpServletResponse response) throws IOException {
        AuthRequest authRequest = getAuthRequest(source);
        response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
    }

    @ApiOperation("发起授权登录-返回第三方授权地址")
    @GetMapping("/login/{source}")
    public R<String> login(@PathVariable("source")String source){
        AuthRequest authRequest = getAuthRequest(source);
        return DataResult.ok(authRequest.authorize(AuthStateUtils.createState()),"ok");
    }

    @ApiOperation("授权回调")
    @RequestMapping("/callback/{platform}")
    public void callback(@PathVariable("platform")String platform, AuthCallback callback,HttpServletResponse response) throws IOException {
        AuthRequest authRequest = getAuthRequest(platform);
        AuthResponse<AuthUser> authResponse = authRequest.login(callback);
        UserInfoVo user = null;
        if(authResponse.ok()){
            AuthUser authUser = authResponse.getData();
            user = userInfoService.getUserInfoByUnionIdAndPlatform(authUser.getUuid(),platform);
            if(Objects.isNull(user)){
                user = userInfoService.createUser(authUser);
            }
            authStateRedisCache.cacheUser(user);
            authStateRedisCache.cacheAuthUser(authUser, user.getPlatform(), user.getId());
            authStateRedisCache.cacheToken(user);
        }
        response.sendRedirect("http://localhost:3000?secret=" + (Objects.isNull(user) ? "":user.getSecret()));
    }

    @ApiOperation("登录成功-获取用户token")
    @GetMapping("/getToken")
    public R<Object> getToken(@RequestHeader("secret") String secret) {
        String token = authStateRedisCache.getToken(secret);
        if(CharSequenceUtil.isNotBlank(token)){
            return DataResult.ok(token,"ok");
        }else {
            return DataResult.fail(HttpStatus.FORBIDDEN,"授权过期或无效");
        }
    }

    @AuthCheck
    @ApiOperation("登录成功-获取用户信息")
    @GetMapping("/getUserInfo")
    public R<UserInfoVo> getUserInfo(@RequestHeader("token") String token) {
        UserInfoVo user = authStateRedisCache.getUserCacheByToken(token);
        if(Objects.nonNull(user)){
            return DataResult.ok(user);
        }else {
            return DataResult.fail(HttpStatus.FORBIDDEN,"授权过期");
        }

    }

    @AuthCheck
    @ApiOperation("登录成功-获取第三方授权信息")
    @GetMapping("/getUserAuth")
    public R<AuthUser> getAuth(@RequestHeader("token") String token) {
        UserInfoVo user = authStateRedisCache.getUserCacheByToken(token);
        if(Objects.nonNull(user)){
            AuthUser authUser = authStateRedisCache.getAuthUser(user.getPlatform(), user.getId());
            return DataResult.ok(authUser);
        }
        return DataResult.fail();
    }

    @AuthCheck
    @ApiOperation("退出登陆")
    @GetMapping("/logout")
    public R<Object> logout(@RequestHeader("token") String token) {
        authStateRedisCache.logout(token);
        return DataResult.ok();
    }

    private AuthDefaultRequest getAuthRequest(String platform) {
        switch (platform){
            case "dingtalk":
                return new AuthDingTalkRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),authStateRedisCache);
            case "gitee":
                return new AuthGiteeRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .scopes(Collections.singletonList(AuthGiteeScope.USER_INFO.getScope()))
                        .build(), authStateRedisCache);
            case "alipay":
               return new AuthAlipayRequest(AuthConfig.builder()
                        //APPID
                        .clientId(oauthConfigProperties.getClientId(platform))
                        //应用私钥
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),oauthConfigProperties.getValue(platform,"alipayPublicKey"),authStateRedisCache);
            case "wechat_enterprise":
                return new AuthWeChatEnterpriseQrcodeRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .agentId(oauthConfigProperties.getValue(platform,"agentId"))
                        .build(),authStateRedisCache);
            case "huawei":
                return new AuthHuaweiRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),authStateRedisCache);
            case "github":
                return new AuthGithubRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),authStateRedisCache);
            case "oschina":
                return new AuthOschinaRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),authStateRedisCache);
            case "baidu":
                return new AuthBaiduRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .build(),authStateRedisCache);
            case "coding":
                return new AuthCodingRequest(AuthConfig.builder()
                        .clientId(oauthConfigProperties.getClientId(platform))
                        .clientSecret(oauthConfigProperties.getSecret(platform))
                        .redirectUri(oauthConfigProperties.getRedirectUri(platform))
                        .domainPrefix(oauthConfigProperties.getValue(platform,"team"))
                        .build());
            default:
            return null;
        }
    }
}
